package My

import (
	"database/sql"
	"fmt"
	"db2s/global"
	"db2s/go-log/log"
	"db2s/osResourceMonitor"
	"db2s/parDef"
	"reflect"
	"strconv"
	"strings"
	"time"
)

var (
	WLog                *log.Logger
	rowsStaticParameter = map[string]any{
		//"group_replication_single_primary_fast_mode": 1,                  //greatDB 优化认证库的参数，不开启在大量数据迁移时，内存会越来越高，写入会越来越慢，对mgr单节点无效
		"innodb_flush_method":      "o_direct_no_sync", //innodb_flush_method：该参数定义InnoDB存储引擎刷新数据和日志文件到磁盘的方法。对于批量插入操作，可以将该参数设置为O_DIRECT，以直接将数据写入磁盘而不经过操作系统缓存。这可以提高性能，尤其是在高负载环境中。
		"innodb_doublewrite":       "off",              //关闭innodb的双写
		"innodb_autoinc_lock_mode": 2,                  //该参数定义了自增长（auto-increment）列的锁定模式。对于批量插入操作，可以将该参数设置为2（interleaved）或0（consecutive），以减少自增长锁的竞争，并提高性能。
		"innodb_io_capacity":       4000,               //该参数用于控制InnoDB存储引擎对磁盘I/O操作的预期能力。对于批量插入操作，可以适当增加innodb_io_capacity的值，以提高磁盘I/O的吞吐量，从而加快数据写入速度。
		"innodb_log_file_size":     10737418240,        //该参数定义InnoDB存储引擎的事务日志文件的大小。增大innodb_log_file_size的值可以提高日志写入性能，尤其是在批量插入操作时。
	}
	rowsDynamicParameter = map[string]any{
		"max_allowed_packet":             1073741824, //设置网络传输包大小
		"bulk_insert_buffer_size":        1073741824, //设置插入操作缓冲区大小
		"innodb_log_buffer_size":         1073741824, //设置innodb_lob_buffer
		"innodb_flush_log_at_trx_commit": 0,          //修改事务提交落盘方式
		"sync_binlog":                    0,          //修改binlog提交落盘方式
		"innodb_change_buffering":        "all",      //使用插入缓冲
		"innodb_flush_log_at_timeout":    30,         //参数定义了刷新事务日志的时间间隔。它接受一个整数值，表示以秒为单位的时间间隔。当经过指定的时间间隔后，无论是否有新的事务提交，都会将事务日志刷新到磁盘。
		//"innodb_buffer_pool_size":                  70,         //该参数用于设置InnoDB存储引擎的缓冲池大小，即内存中用于缓存数据和索引的区域。增大innodb_buffer_pool_size的值可以提高读取性能，尤其是对于频繁访问的数据
		//"group_replication_transaction_size_limit": 0, //设置mgr事务大小
		"net_buffer_length":           1048576,
		"innodb_log_write_ahead_size": 16384, //innodb redo log缓冲大小，记录数据库中的变更操作。写入日志是在事务提交之前发生的，以确保数据的持久性和一致性。为了提高写入性能，InnoDB 使用了一种称为日志预写入（write-ahead log）的机制，它将日志缓冲区中的数据预写入到日志文件中（字节为单位），该参数的默认值为 8192（8KB）。较大的值可以增加 InnoDB 在执行写入操作时的预写入能力，从而提高写入性能。然而，过大的值可能会占用过多的内存资源。
		"innodb_lru_scan_depth":       2048,  //控制 InnoDB LRU（Least Recently Used）算法的扫描深度,nnoDB 存储引擎使用 LRU 算法来管理内存中的数据页，以优化数据的访问性能。LRU 算法根据最近访问的时间来决定哪些数据页应该保留在内存中，以及哪些数据页可以被替换出去。 innodb_lru_scan_depth 参数用于指定 InnoDB 在执行 LRU 扫描时的深度。深度表示每次扫描过程中 InnoDB 考虑的数据页数量。较大的 innodb_lru_scan_depth 值可以增加 LRU 算法的精度，提高数据访问的效率，但同时也会增加 CPU 和内存的消耗,该参数的默认值为 1024，表示每次 LRU 扫描时考虑的数据页数量为 1024 个。可以根据系统的负载和性能需求来调整该值。如果系统的负载较高且内存资源充足，可以考虑增加 innodb_lru_scan_depth 的值以提高 LRU 算法的效果。相反，如果系统的负载较低或内存资源有限，可以适当减小该值以节省资源。
		//"innodb_max_dirty_pages_pct":  75,    //innodb控制脏页最大比例，默认值为75，超过75%将启动后台线程来加快脏页的刷新速度，以避免脏页积累过多导致性能下降，较高的值可以降低磁盘刷脏频率，减少io
		"innodb_adaptive_hash_index": 0,     //关闭hash index，减少truncate的时间，因为执行truncate时，该参数会将buff pool中热数据刷盘
		"foreign_key_checks":         "off", //关闭外键检查
		"innodb_thread_concurrency": func() (lsCpu int) {
			if ll, err := osResourceMonitor.NewCpuObject().Count(true); err != nil {
				return
			} else {
				lsCpu = ll.(int)
			}
			return
		}(), //当innodb_thread_concurrency>0，则表示有 并发数限制，当一个新的请求发起时，会检查当前并发线程数是否达到了 innodb_thread_concurrency的限制值，如果有，则需要sleep一段时间（sleep的设置详见下一部分），然后再再次请求，如果再次请求时，当前并发数还是达到限制值
		"slow_query_log":     "off",
		"general_log":        "off",
		"innodb_strict_mode": "off",
	}
	metaDynamicParameter = map[string]any{
		"innodb_strict_mode": "off", //对于多列（通常大于200列）时，会报ERROR 1118 (42000): Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline，关闭此参数
	}
	metaStaticParameter = map[string]any{
		"innodb_flush_method":      "o_direct_no_sync", //innodb_flush_method：该参数定义InnoDB存储引擎刷新数据和日志文件到磁盘的方法。对于批量插入操作，可以将该参数设置为O_DIRECT，以直接将数据写入磁盘而不经过操作系统缓存。这可以提高性能，尤其是在高负载环境中。
		"innodb_doublewrite":       "off",              //关闭innodb的双写
		"innodb_autoinc_lock_mode": 2,                  //该参数定义了自增长（auto-increment）列的锁定模式。对于批量插入操作，可以将该参数设置为2（interleaved）或0（consecutive），以减少自增长锁的竞争，并提高性能。
		"innodb_io_capacity":       4000,               //该参数用于控制InnoDB存储引擎对磁盘I/O操作的预期能力。对于批量插入操作，可以适当增加innodb_io_capacity的值，以提高磁盘I/O的吞吐量，从而加快数据写入速度。
		"innodb_log_file_size":     10737418240,        //该参数定义InnoDB存储引擎的事务日志文件的大小。增大innodb_log_file_size的值可以提高日志写入性能，尤其是在批量插入操作时。
	}
	classModeParameter = map[string]reflect.Value{
		"struct": reflect.ValueOf(singleDbStructParameter),
		"sync":   reflect.ValueOf(singleDbSyncParameter),
	}
	modeP = map[string]reflect.Value{
		"struct": reflect.ValueOf(StructP),
		"sync":   reflect.ValueOf(syncP),
	}
)

type QueryTable struct {
	Schema              string
	Table               string
	LowerCaseTableNames bool
	ColumnName          []string
	TableColumn         []map[string]string
	IndexColumnDataType string
	SqlExecStopTime     time.Duration
	//DB                  *sql.DB
	LogThreadSeq     int64
	event            string
	MissIndexTablePx string
	FixRows          int64
	SqlMode          bool
	Eas              global.EncryptionProperties
	Scn              string
	PartitionName    string
	PartitionId      string
}
type TableMeta struct {
	Schema              string
	Table               string
	LowerCaseTableNames bool
	ColumnName          []string
	TableColumn         []map[string]string
	IndexColumnDataType string
	SqlExecStopTime     time.Duration
	LogThreadSeq        int64
	event               string
	MissIndexTablePx    string
}
type CollectSlowLog struct {
	LogSeq          int64
	Event           string
	SqlExecStopTime time.Duration
	Db              map[string]*sql.DB
	ReadObject      string //慢日志文件读取对象 file表示读取文件，db表示从数据库自动读取
	SlowLogPath     string //慢日志查询路径
}

var (
	DBType = "MySQL"
	vlog   string
	procP  = func(inout []map[string]interface{}, event string) map[string]string {
		var tmpa = make(map[string]string)
		for _, v := range inout {
			ordinalPosition, err1 := strconv.Atoi(fmt.Sprintf("%v", v["ORDINAL_POSITION"]))
			if err1 != nil {
				fmt.Println(err1)
			}
			specificName := fmt.Sprintf("%v", v["SPECIFIC_NAME"])
			parameterMode := fmt.Sprintf("%v", v["PARAMETER_MODE"])
			if event == "Func" {
				parameterMode = ""
			}
			if _, ok := tmpa["SPECIFIC_NAME"]; !ok && ordinalPosition == 1 {
				tmpa[specificName] = fmt.Sprintf("%v %v %v", parameterMode, v["PARAMETER_NAME"], v["DTD_IDENTIFIER"])
			} else if _, ok = tmpa[specificName]; ok && ordinalPosition > 1 {
				if strings.Split(fmt.Sprintf("%v", tmpa[specificName]), " ")[0] == parameterMode {
					tmpa[specificName] = fmt.Sprintf("%v ,%v %v", tmpa[specificName], v["PARAMETER_NAME"], v["DTD_IDENTIFIER"])
				} else {
					tmpa[specificName] = fmt.Sprintf("%v %v ,%v %v", parameterMode, tmpa[specificName], v["PARAMETER_NAME"], v["DTD_IDENTIFIER"])
				}
			}
		}
		return tmpa
	}
	procR = func(createProc []map[string]interface{}, tmpa map[string]string, event string) map[string]string {
		var tmpb = make(map[string]string)
		for _, v := range createProc {
			routineDefinition := fmt.Sprintf("%v", v["ROUTINE_DEFINITION"])
			routineName := strings.ToUpper(fmt.Sprintf("%v", v["ROUTINE_NAME"]))
			tmpb["DEFINER"] = fmt.Sprintf("%v", v["DEFINER"])
			user := strings.Split(fmt.Sprintf("%v", v["DEFINER"]), "@")[0]
			host := strings.Split(fmt.Sprintf("%v", v["DEFINER"]), "@")[1]
			if event == "Proc" {
				tmpb[routineName] = fmt.Sprintf("delimiter $\nCREATE DEFINER='%v'@'%v' PROCEDURE %v(%v) %v$ \ndelimiter ;", user, host, routineName, tmpa[routineName], strings.ReplaceAll(routineDefinition, "\n", ""))
			}
			if event == "Func" {
				tmpb[routineName] = fmt.Sprintf("delimiter $\nCREATE DEFINER='%v'@'%v' FUNCTION %v(%v) %v$ \ndelimiter ;", user, host, routineName, tmpa[routineName], strings.ReplaceAll(routineDefinition, "\n", ""))
			}
		}
		return tmpb
	}
)

type (
	partMetaBaseDataS struct {
		Schema        string `json:"schema"`
		Table         string `json:"table"`
		FirPartName   string `json:"firstPartName"`
		SubPartName   string `json:"subPartName"`
		FirPartSeq    string `json:"firstPartSeq"`
		SubPartSeq    string `json:"subPartSeq"`
		FirPartMeth   string `json:"firstPartMeth"`
		SubPartMeth   string `json:"subPartMeth"`
		FirPartColumn string `json:"firstPartColumn"`
		SubPartColumn string `json:"subPartColumn"`
		PartRule      string `json:"partitionRules"`
		PartComment   string `json:"partComment"`
	}
	partMethBaseResultS struct {
		FirPartResult           []global.PartitionNameRulesS
		SubPartResult           map[string][]global.PartitionNameRulesS
		MethResult              []string
		FirPartColumnNameResult []string
		SubPartColumnNameResult []string
		ColMetaResult           global.AllReturnResult
		ShardResult             []global.PartShardS
		BaseData                []partMetaBaseDataS
	}
	CreateIndexReturnResult struct {
		recover          []global.HeterogeneousConvertRecord
		notNull          []string
		indexSql         string
		indexColumnGarth map[string]int
	}
	getSingleIndexMaxLengthResult struct {
		newIndexColumnMeta map[string][]global.TableMeta
		indexLength        map[string][]int
		indexColumnGarth   map[string]int
		indexMaxLength     map[string]int
	}
	execSqlS struct {
		DB        map[string]*sql.DB
		ShardName string
		Input     global.StartPartConfigInputP
	}
	ExecSqlInputS struct {
		Ss           any
		Event        string
		GisValFunc   func(any) any
		InsertPrefix string
		SelectSqlStr string
		UpdateSqlStr []string
		LobSwitch    bool
		InsertSqlStr any
		Expect       string
		ShardName    string
	}
)

type (
	newExecSqlS struct {
		DB      *sql.DB
		options Options
	}
	SqlFilter struct {
		WhereSql string
		WhereAdd string
	}
	Object struct {
		Schema    string
		Table     string
		Partition string
	}
	Options struct {
		Scn      string
		StopTime time.Duration
		//Esa                 EncryptionProperties
		WhereSql            string
		WhereAdd            string
		SqlMode             bool
		TablePx             string
		FixRows             int64
		LowerCaseTableNames bool
		SqlLogBin           bool //是否忽略binlog
		RowsLimit           int
		SqlFilter           SqlFilter
		RepairMethod        string //应用sql修复方式
	}
	ExecDDL struct {
		Sql string `json:"sqlText"`
	}
	Parameter struct {
		Con     *sql.DB `json:"-"`
		Object  Object  `json:"object"`
		Options Options `json:"options"`
		ExecDDL ExecDDL `json:"execDDL"`
	}
	TableMe struct {
		//Parameter Parameter `json:"parameter"`
	}
	ColumnMe struct {
		//Parameter Parameter `json:"parameter"`
	}
	IndexMe struct {
		//Parameter Parameter `json:"parameter"`
	}
	PartitionMe struct {
		//Parameter Parameter `json:"parameter"`
	}
	ViewMe struct {
		Parameter Parameter `json:"parameter"`
	}
	MViewMe struct {
		Parameter Parameter `json:"parameter"`
	}
	SeqMe struct {}
	JobMe struct {
		Parameter Parameter `json:"parameter"`
	}
	TriggerMe struct {
		Parameter Parameter `json:"parameter"`
	}
	ForeignMe struct {
		Parameter Parameter `json:"parameter"`
	}
	ProcedureMe struct {
		Parameter Parameter `json:"parameter"`
	}
	FuncMe struct {
		Parameter Parameter `json:"parameter"`
	}
	TypeMe struct {
		Parameter Parameter `json:"parameter"`
	}
	PackageMe struct {
		Parameter Parameter `json:"parameter"`
	}
	GolF struct {}
	SumF struct {
		//Parameter Parameter `json:"parameter"`
	}
	RowsF struct{}
	DmlF  struct{}
)
type (
	newPartMetaBaseResultS struct {
		PartRule    any `json:"partRule"`
		SubPartRule any `json:"subPartRule"`
		PartMeth    any `json:"partMeth"`
		PartCol     any `json:"partCol"`
		SubPartCol  any `json:"subPartCol"`
	}
	modifyLogoRecord struct {
		Object   string //对象
		Logo     string //改动标识
		OldValue string
		NewValue string
		Reason   string //转换说明
	}

	MetaBaseInitResult struct {
		columnMeta      []parDef.ColumnMeta
		constraintsMeta []parDef.Constraints
		columnMetaMap   []parDef.ColMetaMapS
		indexMeta       []parDef.IndexColumnMe
		partMe          parDef.PartMetaData
		factor          int
		Character       string
		Collate         string
		Comment         string
		indexColumnUniq map[string]int
		modifyNotNull   []string
		createIndexSql  string
		createTableSql  string
		switchRecord    []modifyLogoRecord
	}
)
type (
	partRulesS struct {
		Name    string `json:"partName"` //分区名
		SubName string `json:"subPartName"`
		Seq     string `json:"seq"`    //分区序号
		SubSum  string `json:"subSum"` //分区数量
		Rules   string `json:"rules"`  //分区规则
	}
	partMethS struct {
		FirstMeth string `json:"first"`
		SubMeth   string `json:"sub"`
	}
	typeModifyRecord struct {
		columnName string
		oldType    string
		newType    string
	}
)
